{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Property Lookup Resolution"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As we saw in the last set of lectures, something odd is happening when our class uses a data descriptor, and instances contain the same attribute name in the instance dictionary."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Contrary to what we expected, the descriptor was **still** used."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This boils down to data vs non-data descriptors. Python has a default way of where it looks for attributes depending on whether the descriptor is a data-descriptor or not."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As I explain the lecture video, for data descriptors Python will choose to use the descriptor attribute (in the class), even if the same symbol is found in the instance dictionary."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's see this again with a simple example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "class IntegerValue:\n",
    "    def __set__(self, instance, value):\n",
    "        print('__set__ called...')\n",
    "        \n",
    "    def __get__(self, instance, owner_class):\n",
    "        print('__get__ called...')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Point:\n",
    "    x = IntegerValue()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "p = Point()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "__set__ called...\n"
     ]
    }
   ],
   "source": [
    "p.x = 100"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "__get__ called...\n"
     ]
    }
   ],
   "source": [
    "p.x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ok, so the descriptor's `__set__` and `__get__` methods were called."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's set an attribute named `x` directly on the instance dictionary:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{}"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "p.__dict__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "p.__dict__['x'] = 'hello'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'x': 'hello'}"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "p.__dict__"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And now let's get the value:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "__get__ called...\n"
     ]
    }
   ],
   "source": [
    "p.x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As you can see the descriptor was **still** used. The same if we set the value:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "__set__ called...\n"
     ]
    }
   ],
   "source": [
    "p.x = 100"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This works this way because we have a **data descriptor** - the instance attributes do not shadow class descriptors of the same name!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The behavior for a non-data descriptor is different, and the shadowing effect is present:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "from datetime import datetime\n",
    "\n",
    "class TimeUTC:\n",
    "    def __get__(self, instance, owner_class):\n",
    "        print('__get__ called...')\n",
    "        return datetime.utcnow().isoformat()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Logger:\n",
    "    current_time = TimeUTC()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "l = Logger()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "__get__ called...\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'2019-07-13T20:47:59.473945'"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "l.current_time"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As you can see the descriptor's `__get__` was called. \n",
    "\n",
    "Now let's inject the same symbol directly into our instance dictionary:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{}"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "l.__dict__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "l.__dict__['current_time'] = 'this is not a timestamp'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'current_time': 'this is not a timestamp'}"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "l.__dict__"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And if we try to get the value for that key:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'this is not a timestamp'"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "l.current_time"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "we get the value stored in the instance dictionary, **not** the descriptor's `__get__` method."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Of course we can go back to \"normal\" by removing that key from the instance dictionary:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "del l.__dict__['current_time']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And now:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "__get__ called...\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'2019-07-13T20:47:59.556109'"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "l.current_time"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "What this means is that for data descriptors, where we usually need instance-based storage, we can actually use the property name itself to store the value in the instance **under the same name**. It will **not** shadow the class attribute (the descriptor instance), and it has no risk of overwriting any existing instance attributes our class may have!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Of course, this assume that the class does not use slots, or at least specifies `__dict__` as one of the slots if it does."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's apply this to a data descriptor under that assumption:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "class ValidString:\n",
    "    def __init__(self, min_length):\n",
    "        self.min_length = min_length\n",
    "        \n",
    "    def __set_name__(self, owner_class, prop_name):\n",
    "        self.prop_name = prop_name\n",
    "        \n",
    "    def __set__(self, instance, value):\n",
    "        if not isinstance(value, str):\n",
    "            raise ValueError(f'{self.prop_name} must be a string.')\n",
    "        if len(value) < self.min_length:\n",
    "            raise ValueError(f'{self.prop_name} must be '\n",
    "                             f'at least {self.min_length} characters.'\n",
    "                            )\n",
    "        instance.__dict__[self.prop_name] = value\n",
    "        \n",
    "    def __get__(self, instance, owner_class):\n",
    "        if instance is None:\n",
    "            return self\n",
    "        else:\n",
    "            return instance.__dict__.get(self.prop_name, None)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Person:\n",
    "    first_name = ValidString(1)\n",
    "    last_name = ValidString(2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "p = Person()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{}"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "p.__dict__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "p.first_name = 'Alex'\n",
    "p.last_name = 'Martelli'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'first_name': 'Alex', 'last_name': 'Martelli'}"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "p.__dict__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('Alex', 'Martelli')"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "p.first_name, p.last_name"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that I am **not** using attributes (either dot notation or `getattr`/`setattr`) when setting and getting the values from the instance `__dict__`. If I did, it would actually be calling the descriptors `__get__` and `__set__` methods, resulting in an infinite recursion!!\n",
    "\n",
    "So be careful with that!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [],
   "source": [
    "class ValidString:\n",
    "    def __init__(self, min_length):\n",
    "        self.min_length = min_length\n",
    "        \n",
    "    def __set_name__(self, owner_class, prop_name):\n",
    "        self.prop_name = prop_name\n",
    "        \n",
    "    def __set__(self, instance, value):\n",
    "        print('calling __set__ ...')\n",
    "        if not isinstance(value, str):\n",
    "            raise ValueError(f'{self.prop_name} must be a string.')\n",
    "        if len(value) < self.min_length:\n",
    "            raise ValueError(f'{self.prop_name} must be '\n",
    "                             f'at least {self.min_length} characters.'\n",
    "                            )\n",
    "        setattr(instance, self.prop_name, value)\n",
    "        \n",
    "    def __get__(self, instance, owner_class):\n",
    "        if instance is None:\n",
    "            return self\n",
    "        else:\n",
    "            return instance.__dict__.get(self.prop_name, None)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Person:\n",
    "    name = ValidString(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "p = Person()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ...\n",
      "calling __set__ ..."
     ]
    },
    {
     "ename": "RecursionError",
     "evalue": "maximum recursion depth exceeded in comparison",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mRecursionError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-31-5d128de2f1ae>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'Alex'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m<ipython-input-28-97f70694cdb7>\u001b[0m in \u001b[0;36m__set__\u001b[0;34m(self, instance, value)\u001b[0m\n\u001b[1;32m     14\u001b[0m                              \u001b[0;34mf'at least {self.min_length} characters.'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     15\u001b[0m                             )\n\u001b[0;32m---> 16\u001b[0;31m         \u001b[0msetattr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minstance\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mprop_name\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     17\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     18\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0m__get__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minstance\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mowner_class\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "... last 1 frames repeated, from the frame below ...\n",
      "\u001b[0;32m<ipython-input-28-97f70694cdb7>\u001b[0m in \u001b[0;36m__set__\u001b[0;34m(self, instance, value)\u001b[0m\n\u001b[1;32m     14\u001b[0m                              \u001b[0;34mf'at least {self.min_length} characters.'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     15\u001b[0m                             )\n\u001b[0;32m---> 16\u001b[0;31m         \u001b[0msetattr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minstance\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mprop_name\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     17\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     18\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0m__get__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minstance\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mowner_class\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mRecursionError\u001b[0m: maximum recursion depth exceeded in comparison"
     ]
    }
   ],
   "source": [
    "p.name = 'Alex'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
